/*
package com.zlx.mall.basic.quartz;



import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zlx.mall.base.entity.ScQuartzJob;
import com.zlx.mall.base.entity.ScQuartzJobLog;
import com.zlx.mall.base.service.IScQuartzJobLogService;
import com.zlx.mall.base.service.IScQuartzJobService;
import com.zlx.mall.basic.common.holder.ApplicationPropertiesHolder;
import com.zlx.mall.basic.datasource.enums.DeleteEnum;
import com.zlx.mall.basic.datasource.enums.StatusEnum;
import com.zlx.mall.basic.util.json.JacksonUtil;
import com.zlx.mall.basic.util.net.NetUtil;
import com.zlx.mall.basic.util.net.SubnetUtil;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.quartz.*;
import org.quartz.listeners.JobListenerSupport;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

*/
/**
 * @author qingke
 **//*

@Slf4j(topic = "quartzLogger")
//@Component
@Order(999)
public class QuartzJobScanRunner implements
        ApplicationRunner,
        ApplicationListener<ContextClosedEvent> {

    */
/** Work Name *//*

    private static final String WORK_NAME = "quartz-job-scan-thread";
    */
/** Work Interval Duration *//*

    private static final Duration WORK_INTERVAL_DURATION = Duration.ofSeconds(10);
    */
/** Work Daemon Thread *//*

    private Thread thread;
    */
/** Work Stop Signal *//*

    private volatile boolean toStop = false;

    */
/** Job Executor *//*

    private static final String LOCAL_ADDRESS = NetUtil.localAddress();
    */
/** Job Cache *//*

    private static final ConcurrentMap<Long, ScQuartzJob> CACHE = new ConcurrentHashMap<>();
    */
/** Job Listener Name *//*

    private static final String JOB_LISTENER_NAME = "JOB_LOG_LISTENER";

    @Resource
    private Scheduler scheduler;
    @Resource
    private IScQuartzJobService quartzJobService;
    @Resource
    private IScQuartzJobLogService quartzJobLogService;

    private void work() {
        log.info("> Job scan, executor: {}", LOCAL_ADDRESS);

        List<ScQuartzJob> jobs = quartzJobService.list(new QueryWrapper<ScQuartzJob>()
                        .eq(ScQuartzJob.JOB_GROUP, ApplicationPropertiesHolder.APPLICATION_NAME)
                        .eq(ScQuartzJob.STATUS, StatusEnum.ENABLE.getIntegerValue())
                        .eq(ScQuartzJob.IS_DELETE, DeleteEnum.EXISTED.getLongValue()))
                .stream()
                .filter(job -> SubnetUtil.checkAllowAddress(job.getExecutors(), LOCAL_ADDRESS))
                .collect(Collectors.toList());

        List<Long> jobIds = new ArrayList<>();

        if (!jobs.isEmpty()) {
            for (ScQuartzJob job : jobs) {
                jobIds.add(job.getId());

                try {
                    ScQuartzJob history = CACHE.get(job.getId());

                    if (history == null) {
                        // create
                        QuartzUtil.createScheduleJob(scheduler, job);
                        CACHE.put(job.getId(), job);
                        log.info("> Job create, {}", job);

                    } else {
                        if (!history.getVersion().equals(job.getVersion())) {
                            // update
                            QuartzUtil.updateScheduleJob(scheduler, job);
                            CACHE.put(job.getId(), job);
                            log.info("> Job update, {}", job);

                        }
                    }

                } catch (SchedulerException e) {
                    log.error("### Job save or update failed, {}", job, e);
                }
            }
        }

        // delete
        List<ScQuartzJob> deleteJobs = CACHE.values().stream()
                .filter(history -> !jobIds.contains(history.getId()))
                .collect(Collectors.toList());

        if (!deleteJobs.isEmpty()) {
            try {
                QuartzUtil.deleteScheduleJobs(scheduler, deleteJobs);
                deleteJobs.forEach(job -> {
                    log.info("> Job remove, {}", job);
                    CACHE.remove(job.getId());
                });
            } catch (SchedulerException e) {
                log.error("### Job delete failed", e);
            }
        }
    }

    @Override
    public void run(ApplicationArguments args) throws SchedulerException {

        thread = new WorkThread();
        thread.setName(WORK_NAME);
        thread.setDaemon(true);
        thread.start();

        scheduler.getListenerManager().addJobListener(new JobListenerSupport() {

            @Override
            public String getName() {
                return JOB_LISTENER_NAME;
            }

            @Override
            public void jobToBeExecuted(JobExecutionContext ctx) {
                log.info("> Job executed, {}", ctx.getJobDetail().getKey());
            }

            @Override
            public void jobWasExecuted(JobExecutionContext ctx, JobExecutionException executionException) {
                JobDetail jobDetail = ctx.getJobDetail();
                JobDataMap jobDataMap = ctx.getMergedJobDataMap();

                try {
                    ScQuartzJobLog jobLog = new ScQuartzJobLog();
                    jobLog.setJobGroup(jobDetail.getKey().getGroup());
                    jobLog.setJobName(jobDetail.getKey().getName());
                    jobLog.setJobClassName(jobDetail.getJobClass().getName());
                    jobLog.setJobData(JacksonUtil.toJsonString(jobDataMap));
                    jobLog.setExecutor(LOCAL_ADDRESS);
                    jobLog.setFireTime(ctx.getFireTime().toInstant().toEpochMilli());
                    jobLog.setJobRunTime(ctx.getJobRunTime());
                    if (executionException != null) {
                        log.error("### Job JobExecutionException, Job: {}", jobLog, executionException);
                        jobLog.setErrorMessage(executionException.getMessage());
                    }
                    jobLog.setCreateTimestamp(Instant.now());

                    quartzJobLogService.save(jobLog);

                } catch (Exception e) {
                    log.error("### Job log service save failed", e);
                }
            }
        });
    }

    @Override
    public void onApplicationEvent(@NotNull ContextClosedEvent event) {
        toStop();
    }

    public void toStop() {
        toStop = true;
        if (thread != null) {
            thread.interrupt();

            try {
                thread.join();
            } catch (InterruptedException e) {
                log.error("### Work Thread Stop Failed.", e);
            }
        }
    }

    class WorkThread extends Thread {
        @Override
        public void run() {
            while (!toStop) {

                // work
                log.info(">>> Start Work: {}", WORK_NAME);
                try {
                    work();
                } catch (Exception e) {
                    if (!toStop) {
                        log.error("### Work Failed.", e);
                    }
                }

                // sleep
                try {
                    TimeUnit.SECONDS.sleep(WORK_INTERVAL_DURATION.getSeconds());
                } catch (InterruptedException e) {
                    if (!toStop) {
                        log.error("### Work Thead Sleep Failed.", e);
                    }
                }

            }
        }
    }


}
*/
